﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using Isuka.Iteration;
using Isuka.Spiritual.Auxiliaries;

namespace Isuka.Spiritual
{
    public sealed partial class RuleReference<T, A> : IRule<T, A>
        where T : IEquatable<T>
        where A : class
    {

        public RuleReference()
        {
            Rule = Rules<T, A>.Epsilon;
        }

        [DebuggerStepThrough]
        RuleResult<T> Invoke(IBidirectionalIterator<T> it, RuleContext<T, A> context, Rules<T, A>.SkipFunc skip)
        {
            return Rule.Rule(it, context, skip);
        }

        Rules<T, A>.RuleFunc RuleGet { get { return Invoke; } }

        /// <summary>
        /// ルールを保持するように定義を上書きする。
        /// </summary>
        public IRule<T, A> Rule
        {
            get;
            set;
        }

        #region IRule<T,A> メンバー

        Rules<T, A>.RuleFunc IRule<T, A>.Rule
        {
            [DebuggerStepThrough]
            get
            {
                return Invoke;
            }
        }

        #endregion

        #region Operators

        public RuleHolder<T, A> this[Action<A> action]
        {
            [DebuggerStepThrough]
            get
            {
                Contract.Requires(action != null);
                return new RuleHolder<T, A>(RuleGet.Act(action));
            }
        }

        public RuleHolder<T, A> this[Action<A, T> action]
        {
            [DebuggerStepThrough]
            get
            {
                Contract.Requires(action != null);
                return new RuleHolder<T, A>(RuleGet.Act(action));
            }
        }

        #endregion

        #region Contract

        [ContractInvariantMethod]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        private void ObjectInvariant()
        {
            Contract.Invariant(Rule != null);
        }

        #endregion
    }
}
